package com.fdb.basic.framework.core.util;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class BeanCompareUtil {
	
	private static Logger logger = LoggerFactory.getLogger(BeanCompareUtil.class);
	
	public static final String KEY_NEW_VALUE = "newValue";
	public static final String KEY_OLD_VALUE = "oldValue";
	
	/**
	 * 比较对象属性的不同
	 * @param beanF
	 * @param beanS
	 * @return
	 */
	public static Map<String, Map<String, Object>> beanDiff(Object beanF, Object beanS) {
		return beanDiff(beanF.getClass(), beanF, beanS, null, null);
	}
	
	/**
	 * 比较对象属性的不同
	 * @param beanF
	 * @param beanS
	 * @param nonCompare 排除不需比较的域
	 * @return
	 */
	public static Map<String, Map<String, Object>> beanDiff(Object beanF, Object beanS, String[] nonCompare) {
		return beanDiff(beanF.getClass(), beanF, beanS, nonCompare, null);
	}
	
	/**
	 * 比较对象属性的不同
	 * @param beanF
	 * @param beanS
	 * @param concatField 联合字段域
	 * @return
	 */
	public static Map<String, Map<String, Object>> beanDiff(Object beanF, Object beanS, Map<String, String> concatField) {
		return beanDiff(beanF.getClass(), beanF, beanS, null, concatField);
	}
	
	/**
	 * 比较对象属性的不同
	 * @param beanF
	 * @param beanS
	 * @param nonCompare 排除不需比较的域
	 * @param concatField 联合字段域
	 * @return
	 */
	public static Map<String, Map<String, Object>> beanDiff(Object beanF, Object beanS, String[] nonCompare, Map<String, String> concatField) {
		return beanDiff(beanF.getClass(), beanF, beanS, nonCompare, concatField);
	}
	
	/**
	 * 比较对象属性的不同
	 * @param clazz 比较类型
	 * @param beanF
	 * @param beanS
	 * @param nonCompare 排除不需比较的域
	 * @param concatField 联合字段域
	 * @return
	 */
	public static Map<String, Map<String, Object>> beanDiff(Class<?> clazz, Object beanF, Object beanS, String[] nonCompare, Map<String, String> concatField) {
    	if (beanF == null || beanS == null) {
            return Collections.emptyMap();
        }
        
    	Map<String, Map<String, Object>> diffMap = new HashMap<String, Map<String, Object>>();
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            
            Arrays.sort(nonCompare);
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();
                if (!key.equals("class")) {
                	
                	//排除不需要比较的
                    if(nonCompare != null && nonCompare.length > 0
                    		&& Arrays.binarySearch(nonCompare, key) >= 0 ) {
                    	continue;
                    }
                	
                	Object valueF = null;
                	Object valueS = null; 
                	try {
                		valueF = BeanUtility.getProptery(beanF, key);
                		valueS = BeanUtility.getProptery(beanS, key);
                	} catch(Exception e) {
                		logger.debug("getProptery error: " + e.getMessage());
                		//报错则不做比较
                		valueF = null;
                		valueS = null;
                	}
                	
                	//System.out.println("bean 1: " + key + "-" + valueF);
                	//System.out.println("bean 2: " + key + "-" + valueS);
                	
                	//同时为空则不做比较
                	if(Objects.isNull(valueF) && Objects.isNull(valueS)) {
                		continue;
                	}
                	
                	//比较标识，不相同则标识为true
                	boolean diffFlag = false;
                	if(property.getPropertyType().isAssignableFrom(String.class)) {
                		//比较字符串
                		if(! (Objects.nonNull(valueF) && Objects.nonNull(valueS) && 
                				((String) valueF).equals((String) valueS))) {
                			
                			diffFlag = true;
                		}
                	} else if(property.getPropertyType().isAssignableFrom(BigDecimal.class)) {
                		//BigDecimal
                		if(! (Objects.nonNull(valueF) && Objects.nonNull(valueS) && 
                				(((BigDecimal) valueF).compareTo((BigDecimal) valueS)) == 0)) {
                			
                			diffFlag = true;
                		}
                		
                	} else if(property.getPropertyType().isAssignableFrom(Double.class)) {
                		//Double
                		if(! (Objects.nonNull(valueF) && Objects.nonNull(valueS) && 
                				(Double.compare((Double) valueF, (Double) valueS)) == 0)) {
                			
                			diffFlag = true;
                		}
                	} else if(property.getPropertyType().isAssignableFrom(Float.class)) {
                		//Float
                		if(! (Objects.nonNull(valueF) && Objects.nonNull(valueS) && 
                				(Float.compare((Float) valueF, (Float) valueS)) == 0)) {
                			
                			diffFlag = true;
                		}
                	} else if(property.getPropertyType().isAssignableFrom(Long.class)) {
                		//Long
                		if(! (Objects.nonNull(valueF) && Objects.nonNull(valueS) && 
                				(((Long) valueF).compareTo((Long) valueS)) == 0)) {
                			
                			diffFlag = true;
                		}
                	} else if(property.getPropertyType().isAssignableFrom(Integer.class)) {
                		//Integer
                		if(! (Objects.nonNull(valueF) && Objects.nonNull(valueS) && 
                				(Long.compare((Integer) valueF, (Integer) valueS)) == 0)) {
                			
                			diffFlag = true;
                		}
                	} else if(property.getPropertyType().isAssignableFrom(Short.class)) {
                		//Short
                		if(! (Objects.nonNull(valueF) && Objects.nonNull(valueS) && 
                				(Short.compare((Short) valueF, (Short) valueS)) == 0)) {
                			
                			diffFlag = true;
                		}
                		
            		} else if(property.getPropertyType().isPrimitive()) {
                		//比较基础类型 
                		if(! (Objects.nonNull(valueF) && Objects.nonNull(valueS) && 
                				(comparePrimitive(valueF, valueS) == 0))) {
                			
                			diffFlag = true;
                		}
                	} else {
                		//其他全部转成String简单比较
                		String fStr = Objects.nonNull(valueF) ? valueF.toString() : "";
                		String sStr = Objects.nonNull(valueS) ? valueS.toString() : "";
                		
                		if(!fStr.equals(sStr)) {
                			diffFlag = true;
                		}
                	}
                	
                	//不相同
                	if(diffFlag) {
                		Map<String, Object> valueMap = new HashMap<String, Object>();
                		String valueNameF = "";
            			String valueNameS = "";
                		if(concatField != null && concatField.containsKey(key)) {
                			String fieldName = concatField.get(key);
                			try {
                				valueNameF = (String) BeanUtility.getProptery(beanF, fieldName);
                				valueNameS = (String) BeanUtility.getProptery(beanS, fieldName);
                        	} catch(Exception e) {
                        		logger.debug("valueName getProptery error: " + e.getMessage());
                        		valueNameF = "";
                        		valueNameS = "";
                        	}
                		}
                			
            			if(StringUtil.isNotEmpty(valueNameF)) {
            				valueMap.put(KEY_NEW_VALUE, valueF + "," + valueNameF);
            			} else {
            				valueMap.put(KEY_NEW_VALUE, valueF);
            			}
            			
            			if(StringUtil.isNotEmpty(valueNameS)) {
            				valueMap.put(KEY_OLD_VALUE, valueS + "," + valueNameS);
            			} else {
            				valueMap.put(KEY_OLD_VALUE, valueS);
            			}
                		diffMap.put(key, valueMap);
                	}
                }
            }
            
        } catch (Exception e) {
            throw new IllegalArgumentException("beanDiff fail: " + e.getMessage(), e);
        }
        
    	return diffMap;
    }
	
	/**
	 * 比较包装类型值
	 * @param v1
	 * @param v2
	 * @return
	 */
	private static int comparePrimitive(Object v1, Object v2) {
		if(v1 instanceof Double && v2 instanceof Double) {
			return Double.compare((Double) v1, (Double) v2);
		} else if(v1 instanceof Float && v2 instanceof Float) {
			return Float.compare((Float) v1, (Float) v2); 
		} else if(v1 instanceof Long && v2 instanceof Long) {
			return Long.compare((Long) v1, (Long) v2);
		} else if(v1 instanceof Short && v2 instanceof Short) {
			return Short.compare((Short) v1, (Short) v2); 
		} else if(v1 instanceof Integer && v2 instanceof Integer) {
			return Integer.compare((Integer) v1, (Integer) v2);
		} else if(v1 instanceof BigDecimal && v2 instanceof BigDecimal) {
			return ((BigDecimal) v1).compareTo((BigDecimal) v2);
		} else {
			return -1;
		}
	}
	
	
}
